The gRPC Framework
Let's take a closer look at what gRPC is and what key features it provides.
Introduction#
API performance is highly dependent on the architecture of the back-end services. Network communication and system scalability are two important factors directly affecting the performance of web services. Technologies like Simple Object Access Protocol (SOAP), JSON-RPC, RESTful services, etc., have some limitations, such as tight coupling, additional processing, header overhead, interoperability issues, and so on. This led Google to develop the "Stubby" project in 2001 to address the problems above for its backends. The gRPC is an extended version of the Stubby project that was made public as free open-source software (F/OSS) by Google in 2015 and was accepted as an incubation project by CNCF in 2017.
What is gRPC?#
gRPC is an RPC framework that achieves high performance by leveraging the multiplexing functionality introduced in HTTP/2 to create logical subchannels to support the following types of connections:
Request-response: The client can send a single request, and the server can reply with a single response.
Client streaming: The client can send multiple requests, and the server can reply with a single response.
Server streaming: The client can send a single request, and the server can reply with multiple responses.
Bidirectional streaming: The client can send multiple requests, and the server can reply with multiple responses.
gRPC internally manages these HTTP/2 streams to create subchannels and abstracts the details from the client at the application level. A generic gRPC client-server communication is illustrated in the diagram below:
The overall workflow of gRPC is the same as the normal RPC architecture. For example, it calls a remote procedure, then the local code abstraction is handled by the gRPC code stub, and it then communicates with the server-side gRPC over an HTTP channel and executes the remote procedure, and finally returns the result. However, gRPC has added a lot of improvements by using HTTP/2 streams and other components that are discussed in the next section.
In gRPC, Protobuf is the default interface definition language (IDL), which provides a mechanism for serializing data into a cross-platform binary format that can compress headers to achieve high performance. gRPC also has a built-in method for generating client and server code stubs to speed up the development process and manage changes later. Although gRPC was released in 2016, it has quickly gained popularity, and companies such as CoreOS, Cisco, Square, Netflix, Carbon3D, Allo, Google Cloud Services, and others are using it in their production environments.
Note: The gRPC core is implemented in only three different languages: C, Java, and Go. However, it officially supports more than a dozen different languages by wrapping these supported languages in a C core, making it suitable for various development environments.
How does gRPC work?#
Before diving into the gRPC communication cycle, let’s look at some of its main components for a better understanding.
Components#
Channel: It’s an HTTP/2 connection associated with a specific server-side endpoint. Clients can also set default properties of gRPC, such as turning compression on or off when creating a channel.
Subchannel: It’s the logical management of HTTP/2 streams within a channel, where each subchannel represents a connection between a client and a server when load balancing across multiple available servers. Each channel has a one-to-many relationship with subchannels.
gRPC also provides some pluggable components that can be added or removed according to business needs. Some of the pluggable components are listed below:
DNS resolver: It’s a DNS service that resolves an endpoint URL to its IP. It can also return multiple IPs against a request based on the number of back-end servers serving that URL.
Load balancer: It’s a scheduler that directs requests to the backend according to the load balancing policy. This enables gRPC to distribute the load of different subchannels among the pool of back-end servers and makes the system highly scalable.
Envoy proxy: It’s an intermediate server for clients (browsers) running on HTTP/1.1, making them compatible with the HTTP/2 protocol. There are several other proxy options available, but this is the most commonly used proxy for gRPC.
Interestingly, the DNS resolver and load balancer are on the client side and decide which gRPC server to choose to create a subchannel. The client-side load balancing technique achieves high performance by avoiding extra hops when using server-side (proxy) load balancing. But it also brings up client trust issues, which may not be an appropriate option when dealing with third-party applications. Therefore, it’s a design decision to consider all the advantages and disadvantages before load balancing on the client or server side.
Communication cycle#
The gRPC framework focuses on managing network connections and RPC calls. Let's start with connection management. We divide the gRPC connection lifecycle into the following 10 major steps:
The client initiates a request to execute a remote procedure call according to the IDL contract specified in the gRPC generated code.
The generated code marshals the data and sends it to the gRPC framework requesting to establish a connection.
The gRPC sends the endpoint URL specified in the metadata of the request to the DNS resolver, which returns the IP addresses of all the back-end servers running on this URL.
The gRPC then sends the received list of IP addresses to the load balancer, which selects one of the back-end servers based on its configuration or load balancing policy.
Once a backend is selected, the gRPC initiates a connection request to the gRPC transport and returns a reference to a gRPC code stub that can be used later to send messages.
The gRPC transport sends an HTTP/2 stream over the wire, which reaches the listener on the server side.
1 of 11
2 of 11
3 of 11
4 of 11
5 of 11
6 of 11
7 of 11
8 of 11
9 of 11
10 of 11
11 of 11
The listener notifies server-gRPC of incoming connection requests to accept or reject the connection.
The server-gRPC accepts the connection, creates a subchannel for it, and returns the reference to the subchannel. A transport stream is created against each subchannel, maintaining separate read and write buffers for sending and receiving data.
Communication takes place over this subchannel by sending RPC calls. A subchannel can send multiple RPC calls, creating a separate stream for each call.
The packets received at the server gRPC are sent to the server stub to unmarshal the data. The server stub performs type conversions and calls the procedure on the server machine.
Each subchannel is associated with a client and a server. Whereas, each stream corresponds to each RPC call. When a new connection request is initiated, a new subchannel might be created with a different backend, making the system highly scalable.
Basic operations in a remote call#
Now that we know how subchannels are created in gRPC, let's go over the basic types of operations supported by gRPC.
Headers: The client shares metadata, such as back-end IP, status, type of connection, and so on, by sending gRPC headers to the server. The server accepts the incoming request and sends back its header containing the reference to the newly created subchannel.
Messages: The client sends a message with an RPC request, then the server receives the request and does the necessary processing, returning a message with a response. The number of messages exchanged between the client and server may vary depending on the connection type.
Half-close: The client sends a half-close status at the end of its message, indicating that the client is now in receive-only mode and can close the connection when the server has finished sending the response.
Trailer: The server sends a trailer at the end of its response with information, such as server load or any errors that occurred during the execution of the code on the server side.
The basic operations are the same for all types of connections, except that they’re batched in unary calls, i.e., the server receives headers, messages, and half-close before sending back its headers, messages, and trailers. The operation flow in the unary call is shown in the following illustrations:
Advantages#
gRPC is evolving rapidly, and new features are added frequently. A list of added benefits is given below:
gRPC is fast and efficient due to the use of binary transport formats and the ability to fine-tune low-level features of the transport protocol. The graph below shows that when used for asynchronous communication between different services, gRPC can produce three times more throughput than most JSON/HTTP implementations (to learn more, see this Google blog post).
It uses machine-readable contracts, allowing it to automatically generate client and server code with a single compiler.
It can support all four types of communication and abstracts out details like timeouts, retries, request cancellations, and so on.
Since the Internet of Things (IoT) devices are resource constrained (limited bandwidth, buffer storage, and so on), gRPC provides data flow control (transfer rate) through intimate control over HTTP.
Pluggable components, such as a resolver, balancer, compressor, and so on, allow developers to precisely set the environment according to business logic.
Disadvantages#
Since gRPC is in a mature state, it also has some limitations:
It lacks native support for browsers and JavaScript applications running in HTTP/1.1, and it requires setting up additional layers to make it work.
Using the default binary format makes debugging and viewing error details more difficult. However, some pluggable components might help in this regard.
Additional software layers can increase complexity and development costs.
Summary#
gRPC is one of the most sophisticated forms of modern RPC frameworks. It abstracts RPC details from client and server and manages connections internally. It also adds flexibility through pluggable components, like load balancers and resolvers. While it claims to be universally adopted, it may not be the best choice for all use cases. For example, when the API is more resource oriented or deals directly with clients implemented in JavaScript, instead of considering gRPC, other options like REST may be more suitable for our needs. Also, it’s a newer technology with more room for improvement compared to REST/HTTP-style architectures.
Quiz
Question 3
Why is gRPC considered to be a better choice for resource-constrained devices?
The gRPC framework provides more control over the HTTP protocol, allowing it to adjust data transfer rates based on client capabilities, which is why it can be considered a better choice when dealing with resource-constrained devices.
3 of 3
GraphQL: A Query Language for APIs
Comparisons of Different API Architecture Styles